#pragma once

#include <memory>

#include "Definitions.h"

namespace MOE
{
	namespace Core
	{

		namespace BasicTypeOperator
		{
			// Defines copy operations for raw, static-sized data.
			template <tSize DataSize>
			void CopyData(tUntypedConstRef fromData, tUntypedRef toData)
			{
				memcpy(toData, fromData, size_t(DataSize));
			}

			// Defines copy operations for raw, known-sized array.
			template <tSize DataSize>
			void CopyArray(tUntypedConstRef fromArray, tUntypedRef toArray, tSize numElements)
			{
				memcpy(toArray, fromArray, size_t(numElements * DataSize));
			}

			template <>
			inline void CopyData<1u>(tUntypedConstRef fromData, tUntypedRef toData)
			{
				*reinterpret_cast<uint8*>(toData) = *reinterpret_cast<const uint8*>(fromData);
			}

			template <>
			inline void CopyData<2u>(tUntypedConstRef fromData, tUntypedRef toData)
			{
				*reinterpret_cast<uint16*>(toData) = *reinterpret_cast<const uint16*>(fromData);
			}

			template <>
			inline void CopyData<4u>(tUntypedConstRef fromData, tUntypedRef toData)
			{
				*reinterpret_cast<uint32*>(toData) = *reinterpret_cast<const uint32*>(fromData);
			}

			template <>
			inline void CopyData<8u>(tUntypedConstRef fromData, tUntypedRef toData)
			{
				*reinterpret_cast<uint64*>(toData) = *reinterpret_cast<const uint64*>(fromData);
			}

			class Bit8TypeOperator
			{
			public:
				static const tSize kSize = 1u;

				static void CopyData(tUntypedConstRef fromData, tUntypedRef toData)
				{
					BasicTypeOperator::CopyData<kSize>(fromData, toData);
				}

				static void CopyArray(tUntypedConstRef fromArray, tUntypedRef toArray, tSize numElements)
				{
					BasicTypeOperator::CopyArray<kSize>(fromArray, toArray, numElements);
				}
			};

			class Bit16TypeOperator
			{
			public:
				static const tSize kSize = 2u;

				static void CopyData(tUntypedConstRef fromData, tUntypedRef toData)
				{
					BasicTypeOperator::CopyData<kSize>(fromData, toData);
				}

				static void CopyArray(tUntypedConstRef fromArray, tUntypedRef toArray, tSize numElements)
				{
					BasicTypeOperator::CopyArray<kSize>(fromArray, toArray, numElements);
				}
			};

			class Bit32TypeOperator
			{
			public:
				static const tSize kSize = 4u;

				static void CopyData(tUntypedConstRef fromData, tUntypedRef toData)
				{
					BasicTypeOperator::CopyData<kSize>(fromData, toData);
				}

				static void CopyArray(tUntypedConstRef fromArray, tUntypedRef toArray, tSize numElements)
				{
					BasicTypeOperator::CopyArray<kSize>(fromArray, toArray, numElements);
				}
			};

			class Bit64TypeOperator
			{
			public:
				static const tSize kSize = 8u;

				static void CopyData(tUntypedConstRef fromData, tUntypedRef toData)
				{
					BasicTypeOperator::CopyData<kSize>(fromData, toData);
				}

				static void CopyArray(tUntypedConstRef fromArray, tUntypedRef toArray, tSize numElements)
				{
					BasicTypeOperator::CopyArray<kSize>(fromArray, toArray, numElements);
				}
			};

			class ReferenceOperator
			{
			public:
				static const tSize kSize = sizeof(tUntypedRef);

				static void CopyData(tUntypedConstRef fromData, tUntypedRef toData)
				{
					BasicTypeOperator::CopyData<kSize>(fromData, toData);
				}

				static void CopyArray(tUntypedConstRef fromArray, tUntypedRef toArray, tSize numElements)
				{
					BasicTypeOperator::CopyArray<kSize>(fromArray, toArray, numElements);
				}
			};

			class NilOperator
			{
			public:
				static const tSize kSize = 0u;

				static void CopyData(tUntypedConstRef fromData, tUntypedRef toData)
				{
				}

				static void CopyArray(tUntypedConstRef fromArray, tUntypedRef toArray, tSize numElements)
				{
				}
			};
		}

		// Defines type operators for all basic types.

		typedef BasicTypeOperator::Bit8TypeOperator Int8TypeOperator;
		typedef BasicTypeOperator::Bit8TypeOperator UInt8TypeOperator;
		typedef BasicTypeOperator::Bit16TypeOperator Int16TypeOperator;
		typedef BasicTypeOperator::Bit16TypeOperator UInt16TypeOperator;
		typedef BasicTypeOperator::Bit32TypeOperator Int32TypeOperator;
		typedef BasicTypeOperator::Bit32TypeOperator UInt32TypeOperator;
		typedef BasicTypeOperator::Bit64TypeOperator Int64TypeOperator;
		typedef BasicTypeOperator::Bit64TypeOperator UInt64TypeOperator;
		typedef BasicTypeOperator::Bit32TypeOperator Float32TypeOperator;
		typedef BasicTypeOperator::Bit64TypeOperator Float64TypeOperator;

	}
}
